package com.thm.tfast.modules.sys.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.thm.tfast.core.constant.RedisKeyConstant;
import com.thm.tfast.core.service.RedisService;
import com.thm.tfast.core.utils.RedisKeyUtil;
import com.thm.tfast.modules.sys.model.SysUser;
import com.thm.tfast.modules.sys.model.SysUserRole;
import com.thm.tfast.modules.sys.model.vo.dict.DictItemVo;
import com.thm.tfast.modules.sys.model.vo.menu.MenuVo;
import com.thm.tfast.modules.sys.model.vo.permission.PermissionVo;
import com.thm.tfast.modules.sys.model.vo.resource.ResourceVo;
import com.thm.tfast.modules.sys.model.vo.role.RoleVo;
import com.thm.tfast.modules.sys.service.SysCacheService;
import com.thm.tfast.modules.sys.service.SysUserRoleService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @ClassName SysUserCacheServiceImpl
 * @Author THM
 * @Date 2022/10/10 11:32
 * @Version 1.0
 * @Description
 */
@Service
@Transactional
public class SysCacheServiceImpl implements SysCacheService {
    @Value("${jwt.tokenHead}")
    private String tokenHead;

    @Resource
    private RedisService redisService;
    @Resource
    private SysUserRoleService sysUserRoleService;

    @Override
    public String getCode(Long key) {
        Object o = redisService.get(RedisKeyUtil.getKey(RedisKeyConstant.CAPTCHA_KEY_PRE, key));
        if (Objects.isNull(o)) return null;
        return String.valueOf(o);
    }

    @Override
    public void setCode(Long key, String verCode) {
        redisService.set(RedisKeyUtil.getKey(RedisKeyConstant.CAPTCHA_KEY_PRE, key), verCode, 300);
    }

    @Override
    public void delCode(Long key) {
        redisService.del(RedisKeyUtil.getKey(RedisKeyConstant.CAPTCHA_KEY_PRE, key));
    }

    @Override
    public String getToken(String username) {
        Object o = redisService.get(RedisKeyUtil.getKey(RedisKeyConstant.TOKEN_KEY_PRE, username));
        if (Objects.isNull(o)) return null;
        return String.valueOf(o);
    }

    @Override
    public void setToken(String username, String token) {
        redisService.set(RedisKeyUtil.getKey(RedisKeyConstant.TOKEN_KEY_PRE, username),
                tokenHead + token,
                RedisKeyConstant.EXPIRE);
    }

    @Override
    public void delToken(String username) {
        redisService.del(RedisKeyUtil.getKey(RedisKeyConstant.TOKEN_KEY_PRE, username));
    }

    @Override
    public SysUser getUser(String username) {
        Object o = redisService.get(RedisKeyUtil.getKey(RedisKeyConstant.SYS_USER_PRE, username));
        if (Objects.isNull(o)) return null;
        return (SysUser) o;
    }

    @Override
    public void setUser(SysUser sysUser) {
        redisService.set(RedisKeyUtil.getKey(RedisKeyConstant.SYS_USER_PRE, sysUser.getUserName()), sysUser, RedisKeyConstant.EXPIRE);
    }

    @Override
    public void delUser(String username) {
        redisService.del(RedisKeyUtil.getKey(RedisKeyConstant.SYS_USER_PRE, username));
    }

    @Override
    public List<RoleVo> getRole(Long userId) {
        Object o = redisService.get(RedisKeyUtil.getKey(RedisKeyConstant.SYS_ROLE_PRE, userId));
        if (Objects.isNull(o)) return null;
        return JSONUtil.toList(StrUtil.toString(o), RoleVo.class);
    }

    @Override
    public void setRole(Long userId, List<RoleVo> roleList) {
        redisService.set(RedisKeyUtil.getKey(RedisKeyConstant.SYS_ROLE_PRE, userId), JSONUtil.toJsonStr(roleList), RedisKeyConstant.EXPIRE);
    }

    @Override
    public void delRole(Long userId) {
        redisService.del(RedisKeyUtil.getKey(RedisKeyConstant.SYS_ROLE_PRE, userId));
    }

    @Override
    public List<MenuVo> getMenu(Long userId) {
        Object o = redisService.get(RedisKeyUtil.getKey(RedisKeyConstant.SYS_MENU_PRE, userId));
        if (Objects.isNull(o)) return null;
        return JSONUtil.toList(StrUtil.toString(o), MenuVo.class);
    }

    @Override
    public void setMenu(Long userId, List<MenuVo> menuList) {
        redisService.set(RedisKeyUtil.getKey(RedisKeyConstant.SYS_MENU_PRE, userId), JSONUtil.toJsonStr(menuList), RedisKeyConstant.EXPIRE);
    }

    @Override
    public void delMenu(Long userId) {
        redisService.del(RedisKeyUtil.getKey(RedisKeyConstant.SYS_MENU_PRE, userId));
    }

    @Override
    public List<PermissionVo> getPermission(Long userId) {
        Object o = redisService.get(RedisKeyUtil.getKey(RedisKeyConstant.SYS_PERMISSION_PRE, userId));
        if (Objects.isNull(o)) return null;
        return JSONUtil.toList(StrUtil.toString(o), PermissionVo.class);
    }

    @Override
    public void setPermission(Long userId, List<PermissionVo> permissionList) {
        redisService.set(RedisKeyUtil.getKey(RedisKeyConstant.SYS_PERMISSION_PRE, userId), JSONUtil.toJsonStr(permissionList), RedisKeyConstant.EXPIRE);
    }

    @Override
    public void delPermission(Long userId) {
        redisService.del(RedisKeyUtil.getKey(RedisKeyConstant.SYS_PERMISSION_PRE, userId));
    }

    @Override
    public void delRoleByRoleId(Long roleId) {
        List<SysUserRole> sysUserRoleList = sysUserRoleService.list(Wrappers
                .<SysUserRole>lambdaQuery()
                .eq(SysUserRole::getRoleId, roleId));
        if (CollectionUtil.isNotEmpty(sysUserRoleList)) {
            List<String> keys = sysUserRoleList
                    .stream()
                    .map(sysUserRole -> RedisKeyUtil.getKey(RedisKeyConstant.SYS_ROLE_PRE, sysUserRole.getUserId()))
                    .collect(Collectors.toList());
            redisService.del(keys);
        }
    }

    @Override
    public void delMenuByRoleId(Long roleId) {
        List<SysUserRole> sysUserRoleList = sysUserRoleService.list(Wrappers
                .<SysUserRole>lambdaQuery()
                .eq(SysUserRole::getRoleId, roleId));
        if (CollectionUtil.isNotEmpty(sysUserRoleList)) {
            List<String> keys = sysUserRoleList
                    .stream()
                    .map(sysUserRole -> RedisKeyUtil.getKey(RedisKeyConstant.SYS_MENU_PRE, sysUserRole.getUserId()))
                    .collect(Collectors.toList());
            redisService.del(keys);
        }
    }

    @Override
    public void delPermissionByRoleId(Long roleId) {
        List<SysUserRole> sysUserRoleList = sysUserRoleService.list(Wrappers
                .<SysUserRole>lambdaQuery()
                .eq(SysUserRole::getRoleId, roleId));
        if (CollectionUtil.isNotEmpty(sysUserRoleList)) {
            List<String> keys = sysUserRoleList
                    .stream()
                    .map(sysUserRole -> RedisKeyUtil.getKey(RedisKeyConstant.SYS_PERMISSION_PRE, sysUserRole.getUserId()))
                    .collect(Collectors.toList());
            redisService.del(keys);
        }
    }

    @Override
    public List<ResourceVo> getResource() {
        Long length = redisService.lSize(RedisKeyConstant.SYS_RESOURCE_PRE);
        if (length == 0) return null;
        List<Object> objects = redisService.lRange(RedisKeyConstant.SYS_RESOURCE_PRE, 0, length);
        if (CollectionUtil.isNotEmpty(objects)) {
            return BeanUtil.copyToList(objects, ResourceVo.class);
        }
        return null;
    }

    @Override
    public void setResource(List<ResourceVo> resourceList) {
        if (CollectionUtil.isNotEmpty(resourceList)) {
            resourceList.forEach(resourceVo -> redisService.lPush(RedisKeyConstant.SYS_RESOURCE_PRE,
                    resourceVo,
                    RedisKeyConstant.RESOURCE_EXPIRE));
        }
    }

    @Override
    public void delResource() {
        redisService.del(RedisKeyConstant.SYS_RESOURCE_PRE);
    }

    @Override
    public List<DictItemVo> getDict(String type) {
        Long length = redisService.lSize(RedisKeyUtil.getKey(RedisKeyConstant.SYS_DICT_PRE, type));
        if (length == 0) return null;
        List<Object> objects = redisService.lRange(RedisKeyUtil.getKey(RedisKeyConstant.SYS_DICT_PRE, type), 0, length);
        if (CollectionUtil.isNotEmpty(objects)) {
            return BeanUtil.copyToList(objects, DictItemVo.class);
        }
        return null;
    }

    @Override
    public void setDict(String type, List<DictItemVo> dictItemVos) {
        if (CollectionUtil.isNotEmpty(dictItemVos)) {
            dictItemVos.forEach(dictItemVo -> redisService.lPush(RedisKeyUtil.getKey(RedisKeyConstant.SYS_DICT_PRE, type),
                    dictItemVo,
                    RedisKeyConstant.RESOURCE_EXPIRE));
        }
    }

    @Override
    public void delDict(String type) {
        redisService.del(RedisKeyUtil.getKey(RedisKeyConstant.SYS_DICT_PRE, type));
    }
}

